/*   Copyright (C) 2011 Wolfgang Hankeln, Norma J. Wendel
 *
 *   This file is part of CDinFusion.
 *
 *   CDinFusion is free software: you can redistribute it and/or
 *   modify it under the terms of the GNU Lesser General Public 
 *   License in version 3 (LGPL3) as published by the Free Software
 *   Foundation version 3 of the License.
 *
 *   CDinFusion is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   Lesser General Public License for more details.
 *
 *   You should have received a copy of the Lesser General Public
 *   License along with CDinFusion; see the file COPYING. If not,
 *   write to the Free Software Foundation, 59 Temple Place - Suite 330,
 *   Boston, MA 02111-1307, USA or see <http://www.gnu.org/licenses/>.
 *   
 *   If you have any questions, send an email to: megx@mpi-bremen.de.
 */
package org.cdinfusion.filehandling;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.cdinfusion.data.CDElement;
import org.cdinfusion.data.CDFastaHeader;
import org.cdinfusion.data.environment.Air;
import org.cdinfusion.data.environment.Biofilm;
import org.cdinfusion.data.environment.Environment;
import org.cdinfusion.data.environment.Host_associated;
import org.cdinfusion.data.environment.Human_associated;
import org.cdinfusion.data.environment.Human_gut;
import org.cdinfusion.data.environment.Human_oral;
import org.cdinfusion.data.environment.Human_skin;
import org.cdinfusion.data.environment.Human_vaginal;
import org.cdinfusion.data.environment.Miscellaneous;
import org.cdinfusion.data.environment.Plant_associated;
import org.cdinfusion.data.environment.Sediment;
import org.cdinfusion.data.environment.Soil;
import org.cdinfusion.data.environment.Wastewater;
import org.cdinfusion.data.environment.Water;
import org.cdinfusion.data.studytype.BA;
import org.cdinfusion.data.studytype.EU;
import org.cdinfusion.data.studytype.ME;
import org.cdinfusion.data.studytype.MIMARKS_C;
import org.cdinfusion.data.studytype.MIMARKS_S;
import org.cdinfusion.data.studytype.ORG;
import org.cdinfusion.data.studytype.PL;
import org.cdinfusion.data.studytype.StudyType;
import org.cdinfusion.data.studytype.VI;

public class CSVHandler {
	String catalinahome = System.getenv("CATALINA_HOME");
	String folder = catalinahome + "/webapps/CDinFusion/data/";
	String ls = System.getProperty("line.separator");
	String keypairs = "";
	String[] studykey;
	String[] envkey;

	// EMPTY CSV FILE (DOWNLOAD FROM 2a or 2b)
	public String generateEmptyCSV(String studytype, String envtype,
			String sessionID, List<String> seqID) {
		System.out.println("##### CSVHandler #####");
		System.out.println("generateEmptyCSV");

		Timestamp tstamp = new Timestamp(System.currentTimeMillis());
		System.out.println("start generateEmptyCSV tstamp: " + tstamp + " "
				+ tstamp.getTime());

		String message = "";
		keypairs = this.generateStudyKeys(studytype)
				+ this.generateEnvKeys(envtype)
				+ this.generateHeaderKeys(seqID);

		try {
			Writer output = null;
			File file = new File(catalinahome + "/webapps/CDinFusion/data/"
					+ sessionID + ".csv");
			output = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
			output.write(keypairs);
			output.close();
			System.out.println("Your file has been written");
			message = "SUCCESS";
		} catch (Exception e) {
			System.out.println("ERROR in Structured Comment File writer:"
					+ e.getMessage());
			message = "ERROR" + e.getMessage();
		}

		tstamp = new Timestamp(System.currentTimeMillis());
		System.out.println("end generateEmptyCSV tstamp: " + tstamp + " "
				+ tstamp.getTime());

		return message;
	}

	public String generateStudyKeys(String study) {
		System.out.println("generateStudyKeys");

		String studypart = "";
		Field[] fields;
		if (study.equals("none"))
			System.out.println("No studytype selected!");
		if (study.equals("mimarks_s")) {
			MIMARKS_S mimarks_s = new MIMARKS_S();
			fields = mimarks_s.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if mimarks_s

		if (study.equals("mimarks_c")) {
			MIMARKS_C mimarks_c = new MIMARKS_C();
			fields = mimarks_c.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if mimarks_c

		if (study.equals("eu")) {
			EU eu = new EU();
			fields = eu.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if eu

		if (study.equals("ba")) {
			BA ba = new BA();
			fields = ba.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if ba

		if (study.equals("pl")) {
			PL pl = new PL();
			fields = pl.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if pl

		if (study.equals("vi")) {
			VI vi = new VI();
			fields = vi.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if vi

		if (study.equals("orga") | study.equals("org")) {
			ORG orga = new ORG();
			fields = orga.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if orga

		if (study.equals("me")) {
			ME me = new ME();
			fields = me.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if me

		studypart = "DO NOT CHANGE THIS LINE! type of report, " + study + ls;
		if (!study.equals("none")) {
			for (int i = 0; i < studykey.length; i++) {
				studypart = studypart + studykey[i] + "," + ls;
			}
		}
		return studypart;
	}

	public String generateEnvKeys(String env) {
		System.out.println("generateEnvKeys");

		String envpart = "";
		Field[] fields;
		if (env.equals("none"))
			System.out.println("No envtype selected!");
		if (env.equals("water")) {
			Water water = new Water();
			fields = water.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if water

		if (env.equals("wastewater")) {
			Wastewater wastewater = new Wastewater();
			fields = wastewater.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if wastewater

		if (env.equals("soil")) {
			Soil soil = new Soil();
			fields = soil.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if soil

		if (env.equals("sediment")) {
			Sediment sediment = new Sediment();
			fields = sediment.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if sediment

		if (env.equals("plant_associated")) {
			Plant_associated plant_associated = new Plant_associated();
			fields = plant_associated.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if plant_associated

		if (env.equals("miscellaneous")) {
			Miscellaneous miscellaneous = new Miscellaneous();
			fields = miscellaneous.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if miscellaneous

		if (env.equals("biofilm")) {
			Biofilm biofilm = new Biofilm();
			fields = biofilm.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if Biofilm

		if (env.equals("human_vaginal")) {
			Human_vaginal human_vaginal = new Human_vaginal();
			fields = human_vaginal.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if human_vaginal

		if (env.equals("human_skin")) {
			Human_skin human_skin = new Human_skin();
			fields = human_skin.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if human_skin

		if (env.equals("human_oral")) {
			Human_oral human_oral = new Human_oral();
			fields = human_oral.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if human_oral

		if (env.equals("human_gut")) {
			Human_gut human_gut = new Human_gut();
			fields = human_gut.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if human_gut

		if (env.equals("human_associated")) {
			Human_associated human_associated = new Human_associated();
			fields = human_associated.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if human_associated

		if (env.equals("host_associated")) {
			Host_associated host_associated = new Host_associated();
			fields = host_associated.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if host_associated

		if (env.equals("air")) {
			Air air = new Air();
			fields = air.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if air

		envpart = "DO NOT CHANGE THIS LINE! env.package, " + env + ls;
		if (!env.equals("none")) {
			for (int i = 0; i < envkey.length; i++) {
				envpart = envpart + envkey[i] + "," + ls;
			}
		}
		return envpart;
	}

	public String generateHeaderKeys(List<String> seqID) {
		System.out.println("generateHeaderKeys");
		StringBuilder header = new StringBuilder(
				"DO NOT CHANGE THIS LINE! FASTA header,");
		Field[] fields;
		CDFastaHeader cdfheader = new CDFastaHeader();
		fields = cdfheader.getClass().getDeclaredFields();
		String[] cdfhkey = new String[fields.length];
		for (int i = 0; i < fields.length; i++) {
			cdfhkey[i] = fields[i].getName();
		}
		Arrays.sort(cdfhkey);

		if (seqID.size() > 1) {
			header.append(seqID.get(0));
			header.append(", ");
			header.append(seqID.get(seqID.size() - 1));
			header.append(ls);
		} else {
			header.append(seqID.get(0));
			header.append(ls);
		}
		for (int i = 0; i < cdfhkey.length; i++) {
			header.append(cdfhkey[i]);
			header.append(",");
			header.append(ls);
		}
		return header.toString();
	}

	// READ FILLED CSV FILE (UPLOAD FROM 2a)
	public List<CDElement> readCSVfromFile(String file_location,
			String sessionID) throws IOException {
		System.out.println("##### CSVHandler #####");
		System.out.println("readCSVfromFile");

		Timestamp tstamp = new Timestamp(System.currentTimeMillis());
		System.out.println("start readCSVfromFile tstamp: " + tstamp + " "
				+ tstamp.getTime());

		CDElement cdelement = null;
		BufferedReader br = null;
		String studytype = "";
		String envtype = "";
		int where_env = 0;
		int where_cdfh = 0;
		StudyType study = null;
		Environment env = null;
		CDFastaHeader cdfh = null;

		ArrayList<CDElement> cdeList = new ArrayList<CDElement>();

		String seqID = null;
		List<String> seqIDs = new ArrayList<String>();
		String[] seqIds = null;

		List<String> list1 = new ArrayList<String>();
		String[][] values;
		String line = "";
		int j = 0;

		br = new BufferedReader(new FileReader(file_location));
		int a = 0;
		while ((line = br.readLine()) != null) {
			line = line.replaceAll("\"", "");
			list1.add(line);
			a++;
		}
		br.close();
		values = new String[a][2];

		for (int i = 0; i < a; i++) {
			j = list1.get(i).indexOf(",");
			values[i][0] = list1.get(i).substring(0, j);

			values[i][1] = list1.get(i).substring(j + 1);

			if (values[i][0]
					.contains("DO NOT CHANGE THIS LINE! type of report")) {
				studytype = values[i][1];
			}
			if (values[i][0].contains("DO NOT CHANGE THIS LINE! env.package")) {
				envtype = values[i][1];
				where_env = i;
			}
			if (values[i][0].contains("DO NOT CHANGE THIS LINE! FASTA header")) {
				where_cdfh = i;
			}
		}
		study = this.createStudyObject(studytype, values, where_env);
		env = this.createEnvObject(envtype, values, where_env + 1);
		cdfh = this.createCDFHObject(values, where_cdfh + 1);
		seqID = values[where_cdfh][1].toString();

		if (seqID.contains(",")) {
			seqIds = seqID.split(",");
			for (int i = 0; i < seqIds.length; i++) {
				seqIDs.add(seqIds[i].trim());
			}
		} else {
			seqIDs.add(seqID.trim());
		}

		cdelement = new CDElement(seqIDs.get(0), seqIDs.get(seqIDs.size() - 1),
				seqIDs.size(), study, env, cdfh, false);
		cdeList.add(cdelement);

		tstamp = new Timestamp(System.currentTimeMillis());
		System.out.println("end readCSVfromFile tstamp: " + tstamp + " "
				+ tstamp.getTime());

		return (cdeList);
	}

	// STUDY TYPE
	public StudyType createStudyObject(String studytype, String[][] data,
			int end) {
		System.out.println("createStudyObject");
		StudyType obj = null;
		String[] setters;

		if (studytype.contains("mimarks_s")) {
			MIMARKS_S mimarks_s = new MIMARKS_S();
			setters = this.getStudySetters(mimarks_s);
			for (int i = 0; i < setters.length; i++) {
				try {
					if (setters[i].contains("String")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 18);
						mimarks_s.getClass()
								.getMethod(setters[i], String.class)
								.invoke(mimarks_s, data[i + 1][1].toString());
					}
					if (setters[i].contains("(int)")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 5);
						mimarks_s
								.getClass()
								.getMethod(setters[i], int.class)
								.invoke(mimarks_s,
										Integer.parseInt(data[i + 1][1]
												.toString()));
					}
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return mimarks_s;
		}
		if (studytype.contains("mimarks_c")) {
			MIMARKS_C mimarks_c = new MIMARKS_C();
			setters = this.getStudySetters(mimarks_c);
			for (int i = 0; i < setters.length; i++) {
				try {
					if (setters[i].contains("String")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 18);
						mimarks_c.getClass()
								.getMethod(setters[i], String.class)
								.invoke(mimarks_c, data[i + 1][1].toString());
					}
					if (setters[i].contains("(int)")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 5);
						mimarks_c
								.getClass()
								.getMethod(setters[i], int.class)
								.invoke(mimarks_c,
										Integer.parseInt(data[i + 1][1]
												.toString()));
					}
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return mimarks_c;
		}
		if (studytype.contains("eu")) {
			EU eu = new EU();
			setters = this.getStudySetters(eu);
			for (int i = 0; i < setters.length; i++) {
				try {
					if (setters[i].contains("String")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 18);
						eu.getClass().getMethod(setters[i], String.class)
								.invoke(eu, data[i + 1][1].toString());
					}
					if (setters[i].contains("(int)")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 5);
						eu.getClass()
								.getMethod(setters[i], int.class)
								.invoke(eu,
										Integer.parseInt(data[i + 1][1]
												.toString()));
					}
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return eu;
		}
		if (studytype.contains("ba")) {
			BA ba = new BA();
			setters = this.getStudySetters(ba);
			for (int i = 0; i < setters.length; i++) {
				try {
					if (setters[i].contains("String")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 18);
						ba.getClass().getMethod(setters[i], String.class)
								.invoke(ba, data[i + 1][1].toString());
					}
					if (setters[i].contains("(int)")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 5);
						ba.getClass()
								.getMethod(setters[i], int.class)
								.invoke(ba,
										Integer.parseInt(data[i + 1][1]
												.toString()));
					}
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return ba;
		}
		if (studytype.contains("pl")) {
			PL pl = new PL();
			setters = this.getStudySetters(pl);
			for (int i = 0; i < setters.length; i++) {
				try {
					if (setters[i].contains("String")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 18);
						pl.getClass().getMethod(setters[i], String.class)
								.invoke(pl, data[i + 1][1].toString());
					}
					if (setters[i].contains("(int)")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 5);
						pl.getClass()
								.getMethod(setters[i], int.class)
								.invoke(pl,
										Integer.parseInt(data[i + 1][1]
												.toString()));
					}
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return pl;
		}
		if (studytype.contains("vi")) {
			VI vi = new VI();
			setters = this.getStudySetters(vi);
			for (int i = 0; i < setters.length; i++) {
				try {
					if (setters[i].contains("String")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 18);
						vi.getClass().getMethod(setters[i], String.class)
								.invoke(vi, data[i + 1][1].toString());
					}
					if (setters[i].contains("(int)")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 5);
						vi.getClass()
								.getMethod(setters[i], int.class)
								.invoke(vi,
										Integer.parseInt(data[i + 1][1]
												.toString()));
					}
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return vi;
		}
		if (studytype.contains("orga")) {
			ORG orga = new ORG();
			setters = this.getStudySetters(orga);
			for (int i = 0; i < setters.length; i++) {
				try {
					if (setters[i].contains("String")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 18);
						orga.getClass().getMethod(setters[i], String.class)
								.invoke(orga, data[i + 1][1].toString());
					}
					if (setters[i].contains("(int)")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 5);
						orga.getClass()
								.getMethod(setters[i], int.class)
								.invoke(orga,
										Integer.parseInt(data[i + 1][1]
												.toString()));
					}
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return orga;
		}
		if (studytype.contains("me")) {
			ME me = new ME();
			setters = this.getStudySetters(me);
			for (int i = 0; i < setters.length; i++) {
				try {
					if (setters[i].contains("String")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 18);
						me.getClass().getMethod(setters[i], String.class)
								.invoke(me, data[i + 1][1].toString());
					}
					if (setters[i].contains("(int)")) {
						setters[i] = setters[i].substring(0,
								setters[i].length() - 5);
						me.getClass()
								.getMethod(setters[i], int.class)
								.invoke(me,
										Integer.parseInt(data[i + 1][1]
												.toString()));
					}
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return me;
		}
		return (obj);
	}

	public String[] getStudySetters(Object study) {
		System.out.println("getStudySetters");
		String[] methods;
		Method[] meth_all = study.getClass().getDeclaredMethods();

		List<String> find = new ArrayList<String>();
		String find_set = "";
		for (int d = 0; d < meth_all.length; d++) {
			find_set = meth_all[d].toString();
			if (find_set.contains(".set")) {
				find.add(find_set);
			}
		}
		methods = new String[find.size()];
		for (int c = 0; c < methods.length; c++) {
			methods[c] = find.get(c).toString();
		}
		for (int i = 0; i < methods.length; i++) {
			methods[i] = methods[i].replaceAll(
					"public void org.cdinfusion.data.studytype.[A-Z_]{2,10}.",
					"");
		}
		Arrays.sort(methods);
		return (methods);
	}

	// ENV TYPE
	public Environment createEnvObject(String envtype, String[][] data,
			int start) {
		System.out.println("createEnvObject");

		Environment obj = null;
		String[] setters;
		if (envtype.contains("water")) {
			Water water = new Water();
			setters = this.getEnvSetters(water);

			for (int i = 0; i < setters.length; i++) {
				try {
					water.getClass().getMethod(setters[i], String.class)
							.invoke(water, data[start][1]);
					start++;
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return water;
		}
		if (envtype.contains("wastewater")) {
			Wastewater wastewater = new Wastewater();
			setters = this.getEnvSetters(wastewater);

			for (int i = 0; i < setters.length; i++) {
				try {
					wastewater.getClass().getMethod(setters[i], String.class)
							.invoke(wastewater, data[start][1]);
					start++;
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return wastewater;
		}
		if (envtype.contains("soil")) {
			Soil soil = new Soil();
			setters = this.getEnvSetters(soil);

			for (int i = 0; i < setters.length; i++) {
				try {
					soil.getClass().getMethod(setters[i], String.class)
							.invoke(soil, data[start][1]);
					start++;
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return soil;
		}
		if (envtype.contains("sediment")) {
			Sediment sediment = new Sediment();
			setters = this.getEnvSetters(sediment);

			for (int i = 0; i < setters.length; i++) {
				try {
					sediment.getClass().getMethod(setters[i], String.class)
							.invoke(sediment, data[start][1]);
					start++;
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return sediment;
		}
		if (envtype.contains("plant_associated")) {
			Plant_associated plant_associated = new Plant_associated();
			setters = this.getEnvSetters(plant_associated);

			for (int i = 0; i < setters.length; i++) {
				try {
					plant_associated.getClass()
							.getMethod(setters[i], String.class)
							.invoke(plant_associated, data[start][1]);
					start++;
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return plant_associated;
		}
		if (envtype.contains("miscellaneous")) {
			Miscellaneous miscellaneous = new Miscellaneous();
			setters = this.getEnvSetters(miscellaneous);

			for (int i = 0; i < setters.length; i++) {
				try {
					miscellaneous.getClass()
							.getMethod(setters[i], String.class)
							.invoke(miscellaneous, data[start][1]);
					start++;
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return miscellaneous;
		}
		if (envtype.contains("biofilm")) {
			Biofilm biofilm = new Biofilm();
			setters = this.getEnvSetters(biofilm);

			for (int i = 0; i < setters.length; i++) {
				try {
					biofilm.getClass().getMethod(setters[i], String.class)
							.invoke(biofilm, data[start][1]);
					start++;
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return biofilm;
		}
		if (envtype.contains("human_vaginal")) {
			Human_vaginal human_vaginal = new Human_vaginal();
			setters = this.getEnvSetters(human_vaginal);

			for (int i = 0; i < setters.length; i++) {
				try {
					human_vaginal.getClass()
							.getMethod(setters[i], String.class)
							.invoke(human_vaginal, data[start][1]);
					start++;
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return human_vaginal;
		}
		if (envtype.contains("human_skin")) {
			Human_skin human_skin = new Human_skin();
			setters = this.getEnvSetters(human_skin);

			for (int i = 0; i < setters.length; i++) {
				try {
					human_skin.getClass().getMethod(setters[i], String.class)
							.invoke(human_skin, data[start][1]);
					start++;
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return human_skin;
		}
		if (envtype.contains("human_oral")) {
			Human_oral human_oral = new Human_oral();
			setters = this.getEnvSetters(human_oral);

			for (int i = 0; i < setters.length; i++) {
				try {
					human_oral.getClass().getMethod(setters[i], String.class)
							.invoke(human_oral, data[start][1]);
					start++;
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return human_oral;
		}
		if (envtype.contains("human_gut")) {
			Human_gut human_gut = new Human_gut();
			setters = this.getEnvSetters(human_gut);

			for (int i = 0; i < setters.length; i++) {
				try {
					human_gut.getClass().getMethod(setters[i], String.class)
							.invoke(human_gut, data[start][1]);
					start++;
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return human_gut;
		}
		if (envtype.contains("human_associated")) {
			Human_associated human_associated = new Human_associated();
			setters = this.getEnvSetters(human_associated);

			for (int i = 0; i < setters.length; i++) {
				try {
					human_associated.getClass()
							.getMethod(setters[i], String.class)
							.invoke(human_associated, data[start][1]);
					start++;
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return human_associated;
		}
		if (envtype.contains("host_associated")) {
			Host_associated host_associated = new Host_associated();
			setters = this.getEnvSetters(host_associated);

			for (int i = 0; i < setters.length; i++) {
				try {
					host_associated.getClass()
							.getMethod(setters[i], String.class)
							.invoke(host_associated, data[start][1]);
					start++;
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return host_associated;
		}
		if (envtype.contains("air")) {
			Air air = new Air();
			setters = this.getEnvSetters(air);

			for (int i = 0; i < setters.length; i++) {
				try {
					air.getClass().getMethod(setters[i], String.class)
							.invoke(air, data[start][1]);
					start++;
				} catch (Exception e) {
					System.out.println("Exception" + e.getMessage());
				}
			}
			return air;
		}
		return (obj);
	}

	public String[] getEnvSetters(Object env) {
		String[] methods;
		Method[] meth_all = env.getClass().getDeclaredMethods();

		List<String> find = new ArrayList<String>();
		for (int d = 0; d < meth_all.length; d++) {
			if (meth_all[d].getName().startsWith("set")) {
				find.add(meth_all[d].getName());
			}
		}
		methods = new String[find.size()];
		for (int c = 0; c < methods.length; c++) {
			methods[c] = find.get(c);
		}
		Arrays.sort(methods);
		return (methods);
	}

	// FASTAHEADER
	public CDFastaHeader createCDFHObject(String[][] data, int start) {
		System.out.println("createCDFHObject");

		CDFastaHeader header = new CDFastaHeader();
		String[] setters = this.getCDFHSetters(header);
		for (int i = 0; i < setters.length; i++) {
			try {
				header.getClass().getMethod(setters[i], String.class)
						.invoke(header, data[start][1]);
				start++;
			} catch (Exception e) {
				System.out.println("Exception" + e.getMessage());
			}
		}
		return (header);
	}

	public String[] getCDFHSetters(Object cdfh) {
		String[] methods;
		Method[] meth_all = cdfh.getClass().getDeclaredMethods();

		List<String> find = new ArrayList<String>();
		for (int d = 0; d < meth_all.length; d++) {
			if (meth_all[d].getName().startsWith("set")) {
				find.add(meth_all[d].getName());
			}
		}
		methods = new String[find.size()];
		for (int c = 0; c < methods.length; c++) {
			methods[c] = find.get(c);
		}
		Arrays.sort(methods);
		return (methods);
	}

	// WRITE FILLED CSV FILE (DOWNLOAD FROM 3a)
	public String generateFilledCSV(CDElement cdelement, final String sessionID) {
		System.out.println("##### CSVHandler #####");
		System.out.println("generateFilledCSV");
		String message = "";
		String print = "";

		Timestamp tstamp = new Timestamp(System.currentTimeMillis());
		System.out.println("start generateFilledCSV tstamp: " + tstamp + " "
				+ tstamp.getTime());

		// studytype
		Object study = cdelement.getStudy();
		String studytype = study.getClass().toString().toLowerCase();
		studytype = studytype.replace("class org.cdinfusion.data.studytype.",
				"");
		String[] keysStudy = this.generateStudyKeyArray(studytype);
		String firstLineStudy = "DO NOT CHANGE THIS LINE! type of report,"
				+ studytype;
		String contentStudy = firstLineStudy
				+ ls
				+ this.generateFilledStudyKeyValuePairs(keysStudy, study,
						this.getStudyGetters(study));
		// envtype
		Object env = cdelement.getEnv();
		String envtype = env.getClass().toString().toLowerCase();
		envtype = envtype.replace("class org.cdinfusion.data.environment.", "");
		String[] keysEnv = this.generateEnvKeyArray(envtype);
		String firstLineEnv = "DO NOT CHANGE THIS LINE! env.package," + envtype;
		String contentEnv = firstLineEnv
				+ ls
				+ this.generateFilledEnvKeyValuePairs(keysEnv, env,
						this.getEnvGetters(env));
		// cdFastaHeader
		CDFastaHeader cdfh = (CDFastaHeader) cdelement.getCDFastaheader();
		String[] keysCDFH = this.generateCDFHKeyArray();
		StringBuilder firstLineCDFH = new StringBuilder(
				"DO NOT CHANGE THIS LINE! FASTA header, ");
		if (cdelement.getNumberOfSequences() > 1) {
			firstLineCDFH.append(cdelement.getFirstSequenceID());
			firstLineCDFH.append(", ");
			firstLineCDFH.append(cdelement.getLastSequenceID());
		} else {
			firstLineCDFH.append(cdelement.getFirstSequenceID());
		}
		String contentCDFH = firstLineCDFH.toString()
				+ ls
				+ this.generateFilledCDFHKeyValuePairs(keysCDFH, cdfh,
						this.getCDFHGetters(cdfh));
		print = contentStudy + contentEnv + contentCDFH;
		try {
			PrintWriter output = null;
			File file = new File(catalinahome + "/webapps/CDinFusion/data/"
					+ sessionID + "_filled.csv");

			output = new PrintWriter(new OutputStreamWriter(
					new FileOutputStream(file), "UTF-8"));

			output.write(print);
			output.close();
			System.out.println("Your file has been written");
			message = "SUCCESS";
		} catch (Exception e) {
			System.out.println("ERROR in Structured Comment File writer:"
					+ e.getMessage());
			message = "ERROR" + e.getMessage();
		}

		tstamp = new Timestamp(System.currentTimeMillis());
		System.out.println("end generateFilledCSV tstamp: " + tstamp + " "
				+ tstamp.getTime());

		return (message);
	}

	// STUDYTYPE
	public String[] generateStudyKeyArray(String study) {
		System.out.println("generateStudyKeyArray");
		Field[] fields = null;
		if (study.equals("none"))
			System.out.println("No studytype selected!");

		if (study.equals("mimarks_s")) {
			MIMARKS_S mimarks_s = new MIMARKS_S();
			fields = mimarks_s.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		} // end if mimarks_s

		if (study.equals("mimarks_c")) {
			MIMARKS_C mimarks_c = new MIMARKS_C();
			fields = mimarks_c.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if mimarks_c

		if (study.equals("eu")) {
			EU eu = new EU();
			fields = eu.getClass().getDeclaredFields();
			
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if eu

		if (study.equals("ba")) {
			BA ba = new BA();
			fields = ba.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if ba

		if (study.equals("pl")) {
			PL pl = new PL();
			fields = pl.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if pl

		if (study.equals("vi")) {
			VI vi = new VI();
			fields = vi.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if vi

		if (study.equals("orga") | study.equals("org")) {
			ORG orga = new ORG();
			fields = orga.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if orga

		if (study.equals("me")) {
			ME me = new ME();
			fields = me.getClass().getDeclaredFields();
			studykey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				studykey[i] = fields[i].getName();
			}
			Arrays.sort(studykey);
		}// end if me
		return (studykey);
	}

	public String[] getStudyGetters(Object study) {
		String[] methods;
		Method[] meth_all = study.getClass().getDeclaredMethods();

		List<String> find = new ArrayList<String>();
		int f = 0;
		for (int d = 0; d < meth_all.length; d++) {
			if (meth_all[d].getName().startsWith("get")) {
				find.add(meth_all[d].getName());
				f++;
			}
		}
		methods = new String[f];
		for (int c = 0; c < f; c++) {
			methods[c] = find.get(c).toString();
		}
		Arrays.sort(methods);
		return (methods);
	}

	public String generateFilledStudyKeyValuePairs(String[] keys,
			Object object, String[] getters) {
		System.out.println("generateFilledStudyKeys");
		StringBuilder content = new StringBuilder();
		for (int i = 0; i < getters.length; i++) {
			try {
				content.append(keys[i]);
				content.append(",");
				content.append(object.getClass()
						.getMethod(getters[i], (Class[]) null)
						.invoke(object, (Object[]) null));
				content.append(ls);
			} catch (Exception e) {
				System.out.println("Exception" + e.getMessage());
			}
		}
		return content.toString();
	}

	// ENVTYPE
	public String[] generateEnvKeyArray(String env) {
		System.out.println("generateEnvKeyArray");
		Field[] fields;
		if (env.equals("none"))
			System.out.println("No envtype selected!");
		if (env.equals("water")) {
			Water water = new Water();
			fields = water.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if water

		if (env.equals("wastewater")) {
			Wastewater wastewater = new Wastewater();
			fields = wastewater.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if wastewater

		if (env.equals("soil")) {
			Soil soil = new Soil();
			fields = soil.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if soil

		if (env.equals("sediment")) {
			Sediment sediment = new Sediment();
			fields = sediment.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if sediment

		if (env.equals("plant_associated")) {
			Plant_associated plant_associated = new Plant_associated();
			fields = plant_associated.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if plant_associated

		if (env.equals("miscellaneous")) {
			Miscellaneous miscellaneous = new Miscellaneous();
			fields = miscellaneous.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if miscellaneous

		if (env.equals("biofilm")) {
			Biofilm biofilm = new Biofilm();
			fields = biofilm.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if Biofilm

		if (env.equals("human_vaginal")) {
			Human_vaginal human_vaginal = new Human_vaginal();
			fields = human_vaginal.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if human_vaginal

		if (env.equals("human_skin")) {
			Human_skin human_skin = new Human_skin();
			fields = human_skin.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if human_skin

		if (env.equals("human_oral")) {
			Human_oral human_oral = new Human_oral();
			fields = human_oral.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if human_oral

		if (env.equals("human_gut")) {
			Human_gut human_gut = new Human_gut();
			fields = human_gut.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if human_gut

		if (env.equals("human_associated")) {
			Human_associated human_associated = new Human_associated();
			fields = human_associated.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if human_associated

		if (env.equals("host_associated")) {
			Host_associated host_associated = new Host_associated();
			fields = host_associated.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if host_associated

		if (env.equals("air")) {
			Air air = new Air();
			fields = air.getClass().getDeclaredFields();
			envkey = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				envkey[i] = fields[i].getName();
			}
			Arrays.sort(envkey);
		}// end if air
		return (envkey);
	}

	public String[] getEnvGetters(Object env) {
		String[] methods;
		Method[] meth_all = env.getClass().getDeclaredMethods();

		List<String> find = new ArrayList<String>();

		int f = 0;
		for (int d = 0; d < meth_all.length; d++) {
			if (meth_all[d].getName().startsWith("get")) {
				find.add(meth_all[d].getName());
				f++;
			}
		}
		methods = new String[f];
		for (int c = 0; c < f; c++) {
			methods[c] = find.get(c).toString();
		}
		Arrays.sort(methods);
		return (methods);
	}

	public String generateFilledEnvKeyValuePairs(String[] keys, Object object,
			String[] getters) {
		System.out.println("generateFilledEnvKeyValuePairs");
		StringBuilder content = new StringBuilder();
		for (int i = 0; i < getters.length; i++) {
			try {
				content.append(keys[i]);
				content.append(",");
				content.append(object.getClass()
						.getMethod(getters[i], (Class[]) null)
						.invoke(object, (Object[]) null));
				content.append(ls);
			} catch (Exception e) {
				System.out.println("Exception" + e.getMessage());
			}
		}
		return content.toString();
	}

	// FASTAHEADER
	public String[] generateCDFHKeyArray() {
		System.out.println("generateCDFHKeyArray");
		Field[] fields;
		CDFastaHeader cdfh = new CDFastaHeader();
		fields = cdfh.getClass().getDeclaredFields();
		String[] cdfhkey = new String[fields.length];
		for (int i = 0; i < fields.length; i++) {
			cdfhkey[i] = fields[i].getName();
		}
		Arrays.sort(cdfhkey);
		return (cdfhkey);
	}

	public String[] getCDFHGetters(Object cdfh) {
		String[] methods;
		Method[] meth_all = cdfh.getClass().getDeclaredMethods();

		List<String> find = new ArrayList<String>();
		int f = 0;
		for (int d = 0; d < meth_all.length; d++) {
			if (meth_all[d].getName().startsWith("get")) {
				find.add(meth_all[d].getName());
				f++;
			}
		}
		methods = new String[f];
		for (int c = 0; c < f; c++) {
			methods[c] = find.get(c).toString();
		}
		Arrays.sort(methods);
		return (methods);
	}

	public String generateFilledCDFHKeyValuePairs(String[] keys, Object object,
			String[] getters) {
		System.out.println("generateFilledCDFHKeyValuePairs");
		StringBuilder content = new StringBuilder();
		for (int i = 0; i < getters.length; i++) {
			try {
				content.append(keys[i]);
				content.append(",");
				content.append(object.getClass()
						.getMethod(getters[i], (Class[]) null)
						.invoke(object, (Object[]) null));
				content.append(ls);
			} catch (Exception e) {
				System.out.println("Exception" + e.getMessage());
			}
		}
		return content.toString();
	}
}